package com.talios.jira.browser.signals;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
import com.talios.jira.JiraException;
import com.talios.jira.browser.JiraItem;
import com.talios.jira.browser.JiraListComboBoxModel;
import com.talios.jira.browser.JiraProjectDetails;
import com.talios.jira.feeds.FeedException;
import com.talios.jira.feeds.SingleIssueFeedBuilder;
import com.talios.jira.idea.JDomSupport;
import com.talios.jira.rpc.JiraRpcClient;
import org.jdom.Element;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by IntelliJ IDEA. User: amrk Date: 21/01/2004 Time: 22:12:57 To change this template use File | Settings |
 * File Templates.
 */
public class JiraServerDetails implements JDOMExternalizable {
    private static final Logger LOGGER = Logger.getInstance("Jira Browser");

    private String baseurl;
    private String username;
    private String password;
    private boolean supportLegacy;
    private boolean useCustomDateFormat;
    private String customDateFormat;

    private boolean supportsRpc;

    private List projectList;
    private JiraRpcClient rpcClient;

    private List issueTypes = new ArrayList();
    private List issuePriorities = new ArrayList();
    private List issueResolutions = new ArrayList();

    public String getBaseurl() {
        return baseurl;
    }

    public void setBaseurl(String baseurl) {

        if (baseurl != null && baseurl.endsWith("/")) {
            baseurl = baseurl.substring(0, baseurl.length() - 1);
        }
        this.baseurl = baseurl;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public boolean getSupportLegacy() {
        return supportLegacy;
    }

    public void setSupportLegacy(boolean supportLegacy) {
        this.supportLegacy = supportLegacy;
    }

    public String getCustomDateFormat() {
        return customDateFormat;
    }

    public void setCustomDateFormat(String customDateFormat) {
        this.customDateFormat = customDateFormat;
    }

    public boolean getUseCustomDateFormat() {
        return useCustomDateFormat;
    }

    public void setUseCustomDateFormat(boolean useCustomDateFormat) {
        this.useCustomDateFormat = useCustomDateFormat;
    }


    /**
     * @jira INTPLUG-4 Support for Multiple Projects
     */
    public JiraServerDetails() {
        projectList = new ArrayList();
    }

    /**
     * @jira INTPLUG-4 Support for Multiple Projects
     */
    public JiraServerDetails(String baseurl, String username, String password, boolean supportLegacy, boolean useCustomDateFormat, String customDateFormat) {
        setBaseurl(baseurl);
        setUsername(username);
        setPassword(password);
        setSupportLegacy(supportLegacy);
        setUseCustomDateFormat(useCustomDateFormat);
        setCustomDateFormat(customDateFormat);

        projectList = new ArrayList();
    }

    /**
     * @jira INTPLUG-4 Support for Multiple Projects
     */
    public void readExternal(Element element) throws InvalidDataException {
        setBaseurl(JDomSupport.getAttributeWithDefault(element, "baseurl", ""));
        setUsername(JDomSupport.getAttributeWithDefault(element, "username", ""));
        setPassword(JDomSupport.getAttributeWithDefault(element, "password", ""));
        setUseCustomDateFormat(Boolean.valueOf(JDomSupport.getAttributeWithDefault(element, "useCustomDateFormat", "false")));
        setCustomDateFormat(JDomSupport.getAttributeWithDefault(element, "customDateFormat", "")); // set default date format

        Element projectsElement = element.getChild("projects");
        if (projectsElement != null) {
            List projectList = projectsElement.getChildren("project");
            for (Object aProjectList : projectList) {
                Element projectElement = (Element) aProjectList;
                JiraProjectDetails projectDetail = new JiraProjectDetails(this);
                projectDetail.readExternal(projectElement);
                getProjectList().add(projectDetail);
            }
        }

    }

    /**
     * @jira INTPLUG-4 Support for Multiple Projects
     * @jira INTPLUG-5 Lookup projects for easy configuration
     */
    public void writeExternal(Element element) throws WriteExternalException {
        if (getBaseurl() != null) {
            element.setAttribute("baseurl", getBaseurl());
        }
        if (getUsername() != null) {
            element.setAttribute("username", getUsername());
        }
        if (getPassword() != null) {
            element.setAttribute("password", getPassword());
        }

        element.setAttribute("useCustomDateFormat", Boolean.valueOf(getUseCustomDateFormat()).toString());

        if (getCustomDateFormat() != null) {
            element.setAttribute("customDateFormat", getCustomDateFormat());
        }

        // Store server configuration
        Element projectsElement = element.getChild("projects");
        if (projectsElement == null) {
            projectsElement = new Element("projects");
            element.addContent(projectsElement);
        }

        // Remove any existing configurations
        projectsElement.removeChildren("project");

        // Write out projects
        if (!projectList.isEmpty()) {
            for (Object aProjectList : projectList) {
                JiraProjectDetails jiraProjectDetails = (JiraProjectDetails) aProjectList;
                Element projectDetail = new Element("project");
                jiraProjectDetails.writeExternal(projectDetail);
                projectsElement.addContent(projectDetail);
            }
        }

    }

    public List getProjectList() {
        return projectList;
    }

    public String getServerURIAttributes() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("&os_username=");
        buffer.append(getUsername());
        buffer.append("&os_password=");
        buffer.append(getPassword());
        return buffer.toString();
    }

    public JiraRpcClient getRpcClient() {
        return getRpcClient(false);
    }

    /**
     * @jira INTPLUG-62 Add Search by Saved Filters feature
     */
    public JiraRpcClient getRpcClient(boolean forceNewClient) {

        if (rpcClient == null || forceNewClient) {
            rpcClient = new JiraRpcClient(this);
        }

        return rpcClient;
    }

    public void refreshLists(Project project) {
        ProgressManager.getInstance().run(new Task.Backgroundable(project, "Refreshing Issues", true) {
            public void run(ProgressIndicator indicator) {

                LOGGER.info("Refreshing server lists for: " + getBaseurl());
                try {
                    JiraRpcClient rpcClient = getRpcClient(true);

                    issuePriorities = rpcClient.getPriorities();
                    issueTypes = rpcClient.getIssueTypes();
                    issueResolutions = rpcClient.getResolutions();

                    for (Object aProjectList : projectList) {
                        JiraProjectDetails jiraProjectDetails = (JiraProjectDetails) aProjectList;
                        jiraProjectDetails.refreshLists();
                    }

                } catch (JiraException e) {
                    // TODO: Display a unobtrusive popup message about the timeout
                    LOGGER.warn("Unable to refreshIssues lists: " + e.getMessage());
                }
            }
        });
    }

    public List getIssueTypes() {
        return issueTypes;
    }

    public JiraListComboBoxModel getIssueTypesModel() {
        return new JiraListComboBoxModel(getIssueTypes());
    }

    public List getIssuePriorities() {
        return issuePriorities;
    }

    public JiraListComboBoxModel getIssuePrioritiesModel() {
        return new JiraListComboBoxModel(getIssuePriorities());
    }

    public List getIssueResolutions() {
        return issueResolutions;
    }

    public JiraListComboBoxModel getIssueResolutionsModel() {
        return new JiraListComboBoxModel(getIssueResolutions());
    }


    public void viewIssueInBrowser(String browser, String key) {
        try {
            String commandLine = browser + ' ' + buildIssueUrl(key, false);
            Runtime.getRuntime().exec(commandLine);
        } catch (IOException e) {
            LOGGER.error("Unable to browse issue: " + e.getMessage(), e);
        }
    }

    public String buildIssueUrl(String key, boolean includeUserDetails) throws UnsupportedEncodingException {
        StringBuffer buf = new StringBuffer();
        buf.append(getBaseurl());
        buf.append("/secure/ViewIssue.jspa");
        buf.append("?key=");
        buf.append(key);

        if (includeUserDetails) {
            buf.append("&os_username=");
            buf.append(URLEncoder.encode(getUsername(), "UTF-8"));
            buf.append("&os_password=");
            buf.append(URLEncoder.encode(getPassword(), "UTF-8"));
        }

        String issueUrl = buf.toString();
        return issueUrl;
    }


    public JiraItem findIssue(String issueKey) {

        SingleIssueFeedBuilder feedBuilder = new SingleIssueFeedBuilder(issueKey);
        try {
            List feedData = new ArrayList(feedBuilder.buildFeedData(new JiraServerDetails[]{this}));
            if (!feedData.isEmpty()) {
                JiraItem item = (JiraItem) feedData.get(0);

                return item;
            } else {
                return null;
            }
        } catch (FeedException e) {
            LOGGER.info("Unable to locate issue: " + e.getMessage(), e);
            return null;
        }
    }
}
